<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>课堂3D点名系统</title>
    <style>
        body {
            margin: 0;
            overflow: hidden;
            background: #000;
            font-family: Arial, sans-serif;
        }
        #canvas-container {
            position: fixed;
            width: 100%;
            height: 100%;
        }
        .controls {
            position: fixed;
            bottom: 30px;
            right: 30px;
            display: flex;
            gap: 15px;
            z-index: 100;
        }
        button {
            padding: 15px 30px;
            font-size: 20px;
            border: none;
            border-radius: 8px;
            cursor: pointer;
            transition: all 0.3s;
            font-weight: bold;
        }
        #startBtn { background: #4CAF50; color: white; }
        #stopBtn { background: #f44336; color: white; }
        #resetBtn { background: #2196F3; color: white; }
        button:hover {
            transform: scale(1.1);
            box-shadow: 0 0 15px rgba(255,255,255,0.5);
        }

        button:disabled {
            opacity: 0.4;
            cursor: not-allowed;
            transform: none;
            box-shadow: none;
            filter: grayscale(100%);
        }

        #uploadBtn {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
        }

        #uploadBtn:hover {
            background: linear-gradient(135deg, #764ba2 0%, #667eea 100%);
        }
        .selected-name {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%) scale(0);
            font-size: 6.5em;
            color: #FFA726;
            font-weight: bold;
            text-shadow: 0 0 20px rgba(255,167,38,0.8);
            z-index: 50;
            transition: all 0.8s ease-out;
            background: rgba(0, 0, 0, 0.8);
            padding: 30px 60px;
            border-radius: 20px;
            border: 4px solid #FFA726;
            box-shadow: 0 0 30px rgba(255,167,38,0.6);
            backdrop-filter: blur(10px);
        }
        .selected-name.show {
            transform: translate(-50%, -50%) scale(1);
        }

        .initial-prompt {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            color: #ffffff;
            font-size: 2.5em;
            font-weight: bold;
            text-align: center;
            z-index: 60;
            background: rgba(0, 0, 0, 0.7);
            padding: 40px 60px;
            border-radius: 20px;
            border: 2px solid #667eea;
            box-shadow: 0 0 30px rgba(102, 126, 234, 0.6);
            backdrop-filter: blur(10px);
            transition: all 0.3s ease;
            cursor: pointer;
        }
        
        .initial-prompt:hover {
            background: rgba(102, 126, 234, 0.2);
            border-color: #FFA726;
            transform: translate(-50%, -50%) scale(1.05);
            box-shadow: 0 0 40px rgba(255, 167, 38, 0.8);
        }

        .initial-prompt .subtitle {
            font-size: 0.6em;
            color: #cccccc;
            margin-top: 20px;
            font-weight: normal;
        }

        .upload-notification {
            position: fixed;
            top: 20px;
            left: 20px;
            background: rgba(0, 0, 0, 0.8);
            color: #00ff88;
            padding: 15px 25px;
            border-radius: 8px;
            font-size: 16px;
            font-weight: bold;
            z-index: 1000;
            border: 1px solid #00ff88;
            box-shadow: 0 0 15px rgba(0, 255, 136, 0.3);
            transition: opacity 0.3s ease;
        }

        .selected-records {
            position: fixed;
            left: 20px;
            top: 80px;
            width: 180px;
            max-height: 70vh;
            background: rgba(0, 0, 0, 0.8);
            border: 2px solid #FFA726;
            border-radius: 10px;
            padding: 15px;
            z-index: 100;
            overflow-y: auto;
            backdrop-filter: blur(10px);
            box-shadow: 0 0 20px rgba(255, 167, 38, 0.3);
            display: none;
        }

        .selected-records h3 {
            color: #FFA726;
            font-size: 18px;
            margin: 0 0 15px 0;
            text-align: center;
            font-weight: bold;
        }

        .selected-records .record-item {
            color: #ffffff;
            font-size: 16px;
            padding: 8px 12px;
            margin: 5px 0;
            background: rgba(255, 167, 38, 0.1);
            border-radius: 5px;
            border-left: 3px solid #FFA726;
            transition: background-color 0.3s ease;
        }

        .selected-records .record-item:hover {
            background: rgba(255, 167, 38, 0.2);
        }

        .selected-records .record-count {
            text-align: center;
            color: #cccccc;
            font-size: 14px;
            margin-top: 10px;
            padding-top: 10px;
            border-top: 1px solid rgba(255, 167, 38, 0.3);
        }
    </style>
</head>
<body>
    <div id="canvas-container"></div>
    <div class="initial-prompt" id="initialPrompt" onclick="document.getElementById('fileInput').click()" style="cursor: pointer;">
        请先上传学生名单
        <div class="subtitle">点击此处选择班级名单文件</div>
    </div>
    <div id="upload-notification" class="upload-notification" style="display: none;"></div>
    <div class="controls">
            <input type="file" id="fileInput" accept=".txt" style="display: none;">
            <button id="startBtn" disabled>开始</button>
            <button id="stopBtn" disabled>停止</button>
            <button id="resetBtn" disabled>重置</button>
            <div id="uploadStatus" style="color: white; margin-top: 10px; font-size: 14px;"></div>
        </div>
    <div class="selected-records" id="selected-records">
        <h3>选中记录</h3>
        <div id="records-list"></div>
        <div class="record-count" id="record-count">已选：0人</div>
    </div>
    
    <div class="selected-name"></div>

    <script src="three.min.js"></script>
    <script src="tween.umd.js"></script>
    <script>
        let scene, camera, renderer, sphere, stars;
        let names = [];
        let selectedNames = new Set();
        let isRotating = false;
        let currentName = null;
        let textMeshes = [];

        function updateSelectedRecords() {
            const recordsList = document.getElementById('records-list');
            const recordCount = document.getElementById('record-count');
            const recordsPanel = document.querySelector('.selected-records');
            
            recordsList.innerHTML = '';
            selectedNames.forEach(name => {
                const div = document.createElement('div');
                div.className = 'record-item';
                div.textContent = name;
                recordsList.appendChild(div);
            });
            recordCount.textContent = `已选：${selectedNames.size}人`;
            
            // 显示/隐藏记录面板
            if (selectedNames.size > 0) {
                recordsPanel.style.display = 'block';
            } else {
                recordsPanel.style.display = 'none';
            }
        }

        function showUploadNotification(count) {
            const notification = document.getElementById('upload-notification');
            notification.textContent = `已加载 ${count} 个学生名单`;
            notification.style.display = 'block';
            notification.style.opacity = '1';
            
            setTimeout(() => {
                notification.style.opacity = '0';
                setTimeout(() => {
                    notification.style.display = 'none';
                }, 300);
            }, 2000);
        }

        // 文件上传处理
        function handleFileUpload(event) {
            const file = event.target.files[0];
            if (!file) return;
            
            const reader = new FileReader();
            reader.onload = function(e) {
                const content = e.target.result;
                names = content.split('\n')
                    .map(name => name.trim())
                    .filter(name => name.length > 0);
                
                // 检查重复名字
                const nameCounts = {};
                names.forEach(name => {
                    nameCounts[name] = (nameCounts[name] || 0) + 1;
                });
                
                const duplicates = Object.entries(nameCounts)
                    .filter(([name, count]) => count > 1)
                    .map(([name, count]) => `${name}(${count}次)`);
                
                if (duplicates.length > 0) {
                    console.warn('发现重复名字：', duplicates);
                }
                
                console.log('原始名字数：', names.length);
                console.log('去重后名字数：', [...new Set(names)].length);
                console.log('名字列表：', [...new Set(names)]);
                
                if (names.length > 0) {
                // 隐藏初始提示
                document.getElementById('initialPrompt').style.display = 'none';
                
                // 初始化按钮状态：开始可用，停止置灰，重置可用
                document.getElementById('startBtn').disabled = false;
                document.getElementById('stopBtn').disabled = true;
                document.getElementById('resetBtn').disabled = false;
                
                // 创建球体并显示
                if (sphere) {
                    scene.remove(sphere);
                }
                createTextSphere();
                
                // 显示左上角通知
                showUploadNotification([...new Set(names)].length);
            } else {
                alert('文件格式错误，请确保每行一个姓名');
            }
            };
            reader.readAsText(file, 'UTF-8');
        }

        // 加载学生名单（仅用于重置功能）
        function loadNames() {
            return new Promise((resolve) => {
                // 现在只返回空数组，强制用户上传文件
                names = [];
                resolve();
            });
        }

        function init() {
            // 创建场景
            scene = new THREE.Scene();
            
            // 创建相机
            camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
            camera.position.z = 360;  // 适中距离，能看到完整球体

            // 创建渲染器
            renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
            renderer.setSize(window.innerWidth, window.innerHeight);
            renderer.setClearColor(0x000000, 1);
            document.getElementById('canvas-container').appendChild(renderer.domElement);

            // 添加光源
            const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
            scene.add(ambientLight);
            const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
            directionalLight.position.set(1, 1, 1);
            scene.add(directionalLight);

            // 创建星空背景
            createStarfield();
            
            // 创建3D文字球体
            createTextSphere();
            
            // 设置球体初始角度，让旋转更自然
            sphere.rotation.x = 0.3;
            sphere.rotation.y = 0.2;

            // 事件监听
            window.addEventListener('resize', onWindowResize);
            document.getElementById('startBtn').addEventListener('click', startRotation);
            document.getElementById('stopBtn').addEventListener('click', stopRotation);
            document.getElementById('resetBtn').addEventListener('click', resetSystem);
        }

        function createStarfield() {
            const starsGeometry = new THREE.BufferGeometry();
            const starPositions = [];

            for(let i = 0; i < 8000; i++) {
                starPositions.push(
                    (Math.random() - 0.5) * 2500,
                    (Math.random() - 0.5) * 2500,
                    (Math.random() - 0.5) * 2500
                );
            }

            starsGeometry.setAttribute('position', new THREE.Float32BufferAttribute(starPositions, 3));
            const starsMaterial = new THREE.PointsMaterial({ 
                color: 0xFFFFFF, 
                size: 0.6,  // 更小的星星
                transparent: true,
                opacity: 0.6
            });
            stars = new THREE.Points(starsGeometry, starsMaterial);
            scene.add(stars);
        }

        function createTextSphere() {
            sphere = new THREE.Group();
            textMeshes = [];

            const radius = 180;  // 适中的球体半径，能看到完整球体
            const totalNames = names.length;

            // 使用Set来去重，确保每个名字只出现一次
            const uniqueNames = [...new Set(names)];
            
            uniqueNames.forEach((name, i) => {
                // 创建文字精灵
                const canvas = document.createElement('canvas');
                const context = canvas.getContext('2d');
                canvas.width = 150;
                canvas.height = 60;
                
                context.font = 'bold 36px Arial';
                context.textAlign = 'center';
                context.textBaseline = 'middle';
                context.fillStyle = selectedNames.has(name) ? '#FFA726' : '#00BCD4';
                context.fillText(name, 75, 30);

                const texture = new THREE.CanvasTexture(canvas);
                const spriteMaterial = new THREE.SpriteMaterial({ 
                    map: texture,
                    transparent: true
                });
                const sprite = new THREE.Sprite(spriteMaterial);
                sprite.scale.set(42, 18, 1);  // 适中的文字显示

                // 球面分布
                const phi = Math.acos(-1 + (2 * i) / uniqueNames.length);
                const theta = Math.sqrt(uniqueNames.length * Math.PI) * phi;

                sprite.position.setFromSphericalCoords(radius, phi, theta);

                sphere.add(sprite);
                textMeshes.push({ sprite, name });
            });

            scene.add(sphere);
        }

        function onWindowResize() {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
        }

        function startRotation() {
            document.querySelector('.selected-name').classList.remove('show');
            isRotating = true;
            
            // 按钮状态：开始置灰，停止可用，重置置灰
            document.getElementById('startBtn').disabled = true;
            document.getElementById('stopBtn').disabled = false;
            document.getElementById('resetBtn').disabled = true;
            
            // 重新创建球体以应用橙色标记
            scene.remove(sphere);
            createTextSphere();
        }

        function stopRotation() {
            isRotating = false;
            
            if (names.length === 0) return;
            
            const randomIndex = Math.floor(Math.random() * names.length);
            currentName = names[randomIndex];
            selectedNames.add(currentName);

            // 动画期间锁定开始按钮
            document.getElementById('startBtn').disabled = true;
            document.getElementById('stopBtn').disabled = true;
            document.getElementById('resetBtn').disabled = true;

            // 球体缩小动画 - 更快且缩得更小
            new TWEEN.Tween(sphere.scale)
                .to({ x: 0.15, y: 0.15, z: 0.15 }, 600)
                .easing(TWEEN.Easing.Quadratic.Out)
                .start();

            new TWEEN.Tween(sphere.position)
                .to({ z: 250 }, 600)
                .easing(TWEEN.Easing.Quadratic.Out)
                .onComplete(() => {
                    document.querySelector('.selected-name').textContent = currentName;
                    document.querySelector('.selected-name').classList.add('show');
                    
                    // 更新选中记录
                    updateSelectedRecords();
                    
                    // 动画结束后恢复开始按钮
                    document.getElementById('startBtn').disabled = false;
                    document.getElementById('resetBtn').disabled = false;
                })
                .start();
        }

        function resetSystem() {
            selectedNames.clear();
            currentName = null;
            
            // 重置球体
            sphere.scale.set(1, 1, 1);
            sphere.position.z = 0;
            
            // 重新创建文字球体
            scene.remove(sphere);
            createTextSphere();
            
            // 隐藏选中姓名
            document.querySelector('.selected-name').classList.remove('show');
            
            // 清空选中记录
            updateSelectedRecords();
            
            // 按钮状态：开始可用，停止置灰，重置可用
            document.getElementById('startBtn').disabled = false;
            document.getElementById('stopBtn').disabled = true;
            document.getElementById('resetBtn').disabled = false;
        }

        // 添加随机旋转变量
        let rotationSpeedX = 0, rotationSpeedY = 0, rotationSpeedZ = 0;
        let lastSpeedChange = 0;
        
        function updateRandomRotation() {
            rotationSpeedX = 0.01;
                    rotationSpeedY = 0.025 + Math.sin(Date.now() * 0.02) * 0.15;
                    rotationSpeedZ = Math.cos(Date.now() * 0.0015) * 0.15;
        }
        
        function animate() {
            requestAnimationFrame(animate);
            TWEEN.update();
            
            if(isRotating) {
                const now = Date.now();
                // 每1-3秒随机改变一次旋转模式和速度
                if (now - lastSpeedChange > 1000 + Math.random() * 2000) {
                    updateRandomRotation();
                    lastSpeedChange = now;
                }
                
                // 应用随机旋转，增加一些突然变向的效果
                sphere.rotation.x += rotationSpeedX;
                sphere.rotation.y += rotationSpeedY;
                sphere.rotation.z += rotationSpeedZ;
                
                // 偶尔添加突然的加速效果
                if (Math.random() < 0.1) {
                    sphere.rotation.x += (Math.random() - 0.5) * 0.1;
                    sphere.rotation.y += (Math.random() - 0.5) * 0.1;
                    sphere.rotation.z += (Math.random() - 0.5) * 0.05;
                }
            }
            
            // 让球体中的所有文字始终面向相机
            sphere.children.forEach(child => {
                if (child instanceof THREE.Sprite) {
                    child.lookAt(camera.position);
                }
            });
            
            // 星星缓慢旋转
            if (stars) {
                stars.rotation.y += 0.0001;
            }
            
            renderer.render(scene, camera);
        }

        // 初始化 - 强制显示提示，等待用户上传
        document.getElementById('fileInput').addEventListener('change', handleFileUpload);
        init();
        animate();
    </script>
</body>
</html>